﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Caching;

namespace CY_MVC.Utility
{
    public static class DataCache
    {
        /// <summary>
        /// 获取对应缓存ID的缓存内容
        /// </summary>
        /// <typeparam name="T">缓存内容的类型</typeparam>
        /// <param name="p_Cachekey">缓存ID</param>
        /// <param name="p_Value">缓存内容</param>
        /// <returns></returns>
        public static bool GetCache<T>(string p_Cachekey, out T p_Value)
        {
            var Res = false;
            p_Value = default(T);
            if (string.IsNullOrEmpty(p_Cachekey))
            {
                throw new Exception("缓存ID不得为空!");
            }
            var tempobject = HttpRuntime.Cache.Get(p_Cachekey);
            if (tempobject != null)
            {
                p_Value = (T)tempobject;
                Res = true;
            }
            return Res;
        }

        /// <summary>
        /// 获取某关键词起始的缓存
        /// </summary>
        /// <param name="p_KeyIndex"></param>
        /// <returns></returns>
        public static IDictionary<string, object> GetCaches(string p_KeyIndex)
        {
            IDictionary<string, object> Res = new Dictionary<string, object>();
            IDictionaryEnumerator CacheEnum = HttpRuntime.Cache.GetEnumerator();
            while (CacheEnum.MoveNext())
            {
                if (CacheEnum.Key.ToString().StartsWith(p_KeyIndex))
                    Res.Add(CacheEnum.Key.ToString(), CacheEnum.Value);
            }
            return Res;
        }

        /// <summary>
        /// 获取所有缓存
        /// </summary>
        /// <returns></returns>
        public static IDictionary<string, object> GetCaches()
        {
            IDictionary<string, object> Res = new Dictionary<string, object>();
            IDictionaryEnumerator CacheEnum = HttpRuntime.Cache.GetEnumerator();
            while (CacheEnum.MoveNext())
            {
                Res.Add(CacheEnum.Key.ToString(), CacheEnum.Value);
            }
            return Res;
        }

        /// <summary>
        /// 删除key缓存
        /// </summary>
        /// <param name="p_Cachekey">缓存ID</param>
        public static void RemoveCache(string p_Cachekey)
        {
            if (string.IsNullOrEmpty(p_Cachekey))
            {
                throw new Exception("缓存ID不得为空!");
            }
            TryRemoveCache(p_Cachekey);
        }

        /// <summary>
        /// 清除某个标识开头的缓存
        /// </summary>
        /// <param name="p_Cachekeyindex">缓存ID开头标识</param>
        public static void ClearCache(string p_Cachekeyindex)
        {
            if (string.IsNullOrEmpty(p_Cachekeyindex))
            {
                throw new Exception("缓存ID开头标识不得为空!");
            }
            TryRemoveMultiCache(p_Cachekeyindex);
        }

        /// <summary>
        /// 清除缓存
        /// </summary>
        public static void ClearCache()
        {
            TryRemoveAllCache();
        }

        /// <summary>
        /// 设置缓存(默认相对保存10分钟)
        /// </summary>
        /// <param name="p_Cachekey">缓存ID</param>
        /// <param name="p_Value">缓存内容</param>
        public static void SetCache(string p_Cachekey, object p_Value)
        {
            if (string.IsNullOrEmpty(p_Cachekey) || p_Value == null)
            {
                throw new Exception("缓存ID:" + (string.IsNullOrEmpty(p_Cachekey) ? "null" : p_Cachekey) + "或缓存内容:" +
                                    (p_Value == null ? "null" : p_Value.ToString()) + "为空!");
            }
            SetCache(p_Cachekey, p_Value, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(30),
                     CacheItemPriority.Low, null);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="p_Cachekey">缓存ID</param>
        /// <param name="p_Value">缓存内容</param>
        /// <param name="p_AbsoluteExpiration">绝对到期时间(不可与相对到期时间同时设置,不设置的话使用Cache.NoAbsoluteExpiration)</param>
        /// <param name="p_SlidingExpiration">相对到期时间(不可与绝对到期时间同时设置,不设置的话使用Cache.NoSlidingExpiration)</param>
        /// <param name="p_CacheItemPriority">缓存的相对优先级</param>
        public static void SetCache(string p_Cachekey, object p_Value, DateTime p_AbsoluteExpiration, TimeSpan p_SlidingExpiration, CacheItemPriority p_CacheItemPriority)
        {
            if (string.IsNullOrEmpty(p_Cachekey) || p_Value == null)
            {
                throw new Exception("缓存ID:" + (string.IsNullOrEmpty(p_Cachekey) ? "null" : p_Cachekey) + "或缓存内容:" +
                                    (p_Value == null ? "null" : p_Value.ToString()) + "为空!");
            }
            SetCache(p_Cachekey, p_Value, null, p_AbsoluteExpiration, p_SlidingExpiration, p_CacheItemPriority, null);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="p_Cachekey">缓存ID</param>
        /// <param name="p_Value">缓存内容</param>
        /// <param name="p_Dependencies">缓存依赖项</param>
        /// <param name="p_AbsoluteExpiration">绝对到期时间(不可与相对到期时间同时设置,不设置的话使用Cache.NoAbsoluteExpiration)</param>
        /// <param name="p_SlidingExpiration">相对到期时间(不可与绝对到期时间同时设置,不设置的话使用Cache.NoSlidingExpiration)</param>
        /// <param name="p_CacheItemPriority">缓存的相对优先级</param>
        public static void SetCache(string p_Cachekey, object p_Value, CacheDependency p_Dependencies, DateTime p_AbsoluteExpiration, TimeSpan p_SlidingExpiration, CacheItemPriority p_CacheItemPriority)
        {
            if (string.IsNullOrEmpty(p_Cachekey) || p_Value == null || p_Dependencies == null)
            {
                throw new Exception("缓存ID:" + (string.IsNullOrEmpty(p_Cachekey) ? "null" : p_Cachekey) + "或缓存内容:" +
                                    (p_Value == null ? "null" : p_Value.ToString()) + "为空!");
            }
            SetCache(p_Cachekey, p_Value, p_Dependencies, p_AbsoluteExpiration, p_SlidingExpiration,
                     p_CacheItemPriority, null);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="p_Cachekey">缓存ID</param>
        /// <param name="p_Value">缓存内容</param>
        /// <param name="p_DependenciesFile">缓存依赖文件</param>
        /// <param name="p_AbsoluteExpiration">绝对到期时间(不可与相对到期时间同时设置,不设置的话使用Cache.NoAbsoluteExpiration)</param>
        /// <param name="p_SlidingExpiration">相对到期时间(不可与绝对到期时间同时设置,不设置的话使用Cache.NoSlidingExpiration)</param>
        /// <param name="p_CacheItemPriority">缓存的相对优先级</param>
        public static void SetCache(string p_Cachekey, object p_Value, string p_DependenciesFile, DateTime p_AbsoluteExpiration, TimeSpan p_SlidingExpiration, CacheItemPriority p_CacheItemPriority)
        {
            if (string.IsNullOrEmpty(p_Cachekey) || p_Value == null)
            {
                throw new Exception("缓存ID:" + (string.IsNullOrEmpty(p_Cachekey) ? "null" : p_Cachekey) + "或缓存内容:" +
                                    (p_Value == null ? "null" : p_Value.ToString()) + "为空!");
            }
            var dependencies = new CacheDependency(p_DependenciesFile);
            SetCache(p_Cachekey, p_Value, dependencies, p_AbsoluteExpiration, p_SlidingExpiration,
                     p_CacheItemPriority, null);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="p_Cachekey">缓存ID</param>
        /// <param name="p_Value">缓存内容</param>
        /// <param name="p_Dependencies">缓存依赖文件</param>
        /// <param name="p_AbsoluteExpiration">绝对到期时间(不可与相对到期时间同时设置,不设置的话使用Cache.NoAbsoluteExpiration)</param>
        /// <param name="p_SlidingExpiration">相对到期时间(不可与绝对到期时间同时设置,不设置的话使用Cache.NoSlidingExpiration)</param>
        /// <param name="p_CacheItemPriority">缓存的相对优先级</param>
        /// <param name="p_OnRemovedCallback">缓存移除事件</param>
        public static void SetCache(string p_Cachekey, object p_Value, CacheDependency p_Dependencies, DateTime p_AbsoluteExpiration, TimeSpan p_SlidingExpiration, CacheItemPriority p_CacheItemPriority, CacheItemRemovedCallback p_OnRemovedCallback)
        {
            if (string.IsNullOrEmpty(p_Cachekey) || p_Value == null)
            {
                throw new Exception("缓存ID:" + (string.IsNullOrEmpty(p_Cachekey) ? "null" : p_Cachekey) + "或缓存内容:" +
                                    (p_Value == null ? "null" : p_Value.ToString()) + "为空!");
            }
            TrySetCache(p_Cachekey, p_Value, p_Dependencies, p_AbsoluteExpiration, p_SlidingExpiration,
                        p_CacheItemPriority, p_OnRemovedCallback);
        }

        #region 缓存基础操作

        /// <summary>
        /// 建立缓存
        /// </summary>
        private static void TrySetCache(string p_Key, object p_Value, CacheDependency p_Dependencies, DateTime p_AbsoluteExpiration, TimeSpan p_SlidingExpiration, CacheItemPriority p_Priority, CacheItemRemovedCallback p_OnRemovedCallback)
        {
            HttpRuntime.Cache.Insert(p_Key, p_Value, p_Dependencies, p_AbsoluteExpiration, p_SlidingExpiration, p_Priority, p_OnRemovedCallback);
        }

        /// <summary>
        /// 移除缓存
        /// </summary>
        private static void TryRemoveCache(string p_Key)
        {
            if (HttpRuntime.Cache[p_Key] == null) return;
            HttpRuntime.Cache.Remove(p_Key);
        }

        /// <summary>
        /// 移除键中带某关键字的缓存
        /// </summary>
        private static void TryRemoveMultiCache(string p_KeyIndex)
        {
            IDictionaryEnumerator CacheEnum = HttpRuntime.Cache.GetEnumerator();
            while (CacheEnum.MoveNext())
            {
                if (!CacheEnum.Key.ToString().StartsWith(p_KeyIndex)) continue;
                HttpRuntime.Cache.Remove(CacheEnum.Key.ToString());
            }
        }

        /// <summary>
        /// 移除所有缓存
        /// </summary>
        private static void TryRemoveAllCache()
        {
            IDictionaryEnumerator CacheEnum = HttpRuntime.Cache.GetEnumerator();
            while (CacheEnum.MoveNext())
            {
                HttpRuntime.Cache.Remove(CacheEnum.Key.ToString());
            }
        }

        #endregion

    }
}
